package com.cloudclassroom.config;

import com.cloudclassroom.filter.JwtAuthenticationFilter;
import com.cloudclassroom.util.JwtUtils;
import com.cloudclassroom.vo.RestResult;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author 92110
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                // 关闭CSRF保护
                .csrf(AbstractHttpConfigurer::disable)
                // 配置保护路径
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers(
                                "/test/**",
                                "/auth/**",
                                "/customer/register",
                                "/swagger-ui/**",
                                "/webjars/**",
                                "/swagger-resources/**",
                                "/v3/api-docs/**"
                        ).permitAll()
                        .anyRequest().authenticated()
                )
                // 禁止明文传输
                .httpBasic(AbstractHttpConfigurer::disable)
                // 使用无状态session
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                //配置跨域请求
                .cors(conf -> {
                    var cors = new CorsConfiguration();
                    cors.addAllowedOrigin("*");
                    cors.addAllowedHeader("*");
                    cors.addAllowedMethod("*");
                    cors.addExposedHeader("*");
                    var source = new UrlBasedCorsConfigurationSource();
                    source.registerCorsConfiguration("/**", cors);
                    conf.configurationSource(source);
                })
                .exceptionHandling(conf -> conf
                        .accessDeniedHandler((response1, e, e2) -> handleAccessDenied(e, e2))
                        .authenticationEntryPoint((response, authenticate, authenticate2) -> handleAuthentication(authenticate, authenticate2))
                )
                // 配置登录路径
                .formLogin(conf -> conf
                        .failureHandler(this::onAuthenticationFailure)
                        .successHandler(this::onAuthenticationSuccess)
                        .permitAll()
                )
                .logout(conf -> conf
                       .logoutUrl("/auth/logout")
                       .logoutSuccessHandler(this::onLogoutSuccess)
                )
                .addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    private void handleAuthentication(HttpServletResponse response,
                                      AuthenticationException authenticate
    ) throws IOException {
        // 设置HTTP响应状态码为401 Unauthorized
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        handleProcess(response, authenticate);
    }

    private void handleAccessDenied(HttpServletResponse response,
                                    AccessDeniedException e
    ) throws IOException {
        // 设置HTTP响应状态码为403 Forbidden
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        handleProcess(response, e);
    }

    private void onAuthenticationFailure(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException exception
    ) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(RestResult.failure(401, exception.getMessage()).toJsonString());
    }

    private void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication
    ) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        System.out.println(authentication.getPrincipal());
        writer.write(RestResult.success(JwtUtils.createJwt((User) authentication.getPrincipal())).toJsonString());
    }

    private void handleProcess(HttpServletResponse response,
                               Object exceptionOrAuthentication) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        if(exceptionOrAuthentication instanceof AccessDeniedException exception) {
            writer.write(RestResult.failure(403, exception.getMessage()).toJsonString());
        } else if(exceptionOrAuthentication instanceof Exception exception) {
            writer.write(RestResult.failure(401, exception.getMessage()).toJsonString());
        } else if(exceptionOrAuthentication instanceof Authentication authentication){
            writer.write(RestResult.success(JwtUtils.createJwt((User) authentication.getPrincipal())).toJsonString());
        }
    }


    private void onLogoutSuccess(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Authentication authentication) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        String authorization = request.getHeader("Authorization");
        if(authorization != null && authorization.startsWith("Bearer ")) {
            String token = authorization.substring(7);
            //将Token加入黑名单
            if(JwtUtils.invalidate(token)) {
                //只有成功加入黑名单才会退出成功
                writer.write(RestResult.success("退出登录成功").toJsonString());
                return;
            }
        }
        writer.write(RestResult.failure(400, "退出登录失败").toJsonString());
    }

}
